using Hangfire;
using Hangfire.Common;
using Hangfire.Dashboard.BasicAuthorization;
using Hangfire.SqlServer;
using Hangfire.Storage;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Quartz.Impl;
using Quartz.Spi;
using Quartz;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Application.AppConfigureManage;
using Zocono.WCS.Comm;
using Zocono.WCS.Domain;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.EquipmentProcessDomain;
using Zocono.WCS.Domain.JobExcutorDomain;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.PlcWriteDbDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Domain.ProgrameDomain;
using Zocono.WCS.Domain.RouteDomain;
using Zocono.WCS.Domain.SocketServiceDomain;
using Zocono.WCS.Domain.WcsGetWmsJobDomain;
using Zocono.WCS.HangfireHost.Hangfire;
using Zocono.WCS.HangfireHost.Hubs;
using Zocono.WCS.HangfireHost.QuartzCore;
using Zocono.WCS.HangfireHost.StartAndStopService;
using Zocono.WCS.WMSApiDomain.WebApi;
using Zocono.WMS.Infrastructure.BaseRepository.SqlSugarUtil;
using Quartz.Impl.AdoJobStore.Common;
using ServiceReference2;
using static Quartz.Logging.OperationName;
using Zocono.WCS.HangfireHost.TaskJobs;
using Zocono.WCS.HangfireHost.QuartzJobs;
using Hangfire.MemoryStorage;

namespace Zocono.WCS.HangfireHost
{
    public class Startup
    {
        public const string CorsName = "SignalRCors";
        IWcsGetWmsJobService _IWcsGetWmsJobService;
        IPlcConnectionPoolService _IPlcConnectionPoolService;
        IServiceCollection _services;
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            _services = services;
            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Zocono.WCS.HangfireHost", Version = "v1" });
            });
            //services.AddSignalR();
            services.AddSignalR(hubOptions =>
            {
                hubOptions.MaximumReceiveMessageSize = null;//解除数量传输限制
                //服务器端向客户端 ping的间隔
                hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(15);
            });
            // 配置跨域访问问题
            services.AddCors(options =>
            {
                options.AddPolicy("all",
                                  builder =>
                                  {
                                      builder.AllowAnyMethod()
                                        // 此处设置为无任何限制
                                        .SetIsOriginAllowed(_ => true)
                                         .AllowAnyHeader()
                                         .AllowCredentials();
                                      // 也可以这样设置：允许指定的域名访问：
                                      // builder.WithOrigins("http://example.com",
                                      //                  "http://www.contoso.com")
                                      //            .AllowAnyMethod()
                                      //            .AllowAnyHeader()
                                      //            .AllowCredentials();
                                  });
            });
            services.AddNlog();
            services.AddScoped<NlogUtilScoped>();
            services.AddAutoMapper(typeof(AutoMapperConfigProfile));
            services.AddRedisCache();
           // services.BindServiceProvider();
            var sqlSugarConfig = SqlSugarConfig.GetConnectionString(Configuration);//连接数据库
            services.AddSqlSugarClient<SqlSugar.SqlSugarClient>(config =>
            {
                config.ConnectionString = sqlSugarConfig.Item2;
                config.DbType = sqlSugarConfig.Item1;
                config.IsAutoCloseConnection = true;
                config.InitKeyType = InitKeyType.Attribute;
                //config.IsShardSameThread = true;
            }, ServiceLifetime.Scoped);

            //注册
            ServiceIOC.AddService(services);
            services.AddSingleton<TaskLock>();
            services.AddScoped<GetScWorkTaskToMeJob>();
            services.AddScoped<GetWmsTaskToWcsJob>();
            services.AddScoped<HeartJob>();
            services.AddScoped<InitPlcConnectPoolJob>();
            services.AddScoped<OnceJobQz>();
            services.AddScoped<PlcReconnectJob>();
            services.AddScoped<RepeatGetTableDataJob>();
            services.AddScoped<RepeatReadDbJob>();

            //1为hangfire  2为Quartz
            string JobType = Configuration["JobType"];
            if (JobType == "2")
            {
                services.AddSingleton<IJobFactory, JobFactory>();
                services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
                services.AddSingleton<IQuartzHelp, QuartzHelp>();
                var transientType = typeof(IJob);
                var allTypes = AppDomain.CurrentDomain.GetAssemblies()
                                .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(transientType)));
                foreach (var item in allTypes)
                {
                    services.AddScoped(item);
                }
            }
            else
            {
                //设置hangfire 已完成的job设置过期，防止数据无限增长
                GlobalStateHandlers.Handlers.Add(new SucceededStateExpireHandler(int.Parse(Configuration["Hangfire:JobExpirationTimeout"])));
                //注册Hangfire        
                var hangfireSetting = Configuration["Hangfire:SqlServerConnectionString"];
                //services.AddHangfire(x => x.UseSqlServerStorage(hangfireSetting,
                //    new SqlServerStorageOptions
                //    {
                //        //TransactionTimeout = TimeSpan.FromSeconds(20),      // 事务超时。默认为1分钟
                //        //JobExpirationCheckInterval = TimeSpan.FromMinutes(3),//作业过期检查间隔（管理过期记录）
                //        CommandBatchMaxTimeout = TimeSpan.FromMinutes(3),// 命令批处理最大超时时间
                //        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(3),//滑动超时
                //        QueuePollInterval = TimeSpan.FromMinutes(5),//队列轮询时间间隔，默认值为15秒
                //        UseRecommendedIsolationLevel = true, // 是否使用建议的隔离级别
                //        UsePageLocksOnDequeue = true, //出列时是否需要锁
                //        DisableGlobalLocks = true, // 是否禁用全局锁,需要迁移到模式7
                //    }).UseTagsWithSql());

                services.AddHangfire(x => x.UseMemoryStorage());

                //注册hangfire服务
                services.AddHangfireServer((p) =>
                {
                    //服务名称
                    p.ServerName = Configuration["Hangfire:ServerName"];
                    //每秒级执行
                    p.SchedulePollingInterval = TimeSpan.FromSeconds(1);
                    //任务线程数
                    p.WorkerCount = Environment.ProcessorCount * int.Parse(Configuration["Hangfire:ProcessorCount"]);
                    //p.ServerTimeout=TimeSpan.FromSeconds(5);
                });
                //services.AddHangfireServer((p) => { p.SchedulePollingInterval = TimeSpan.FromSeconds(1); });

            }

            services.AddHostedServiceExpand();

        }

        public void Configure(IApplicationBuilder app
            , IWebHostEnvironment env
            , IServiceProvider serviceProvider
            , IWcsGetWmsJobService wcsGetWmsJobService
            , IPlcConnectionPoolService plcConnectionPoolService
            ,ILogUtil logUtil)
        {
            ServiceCollectionExt.serviceProvider = app.ApplicationServices;
            _IWcsGetWmsJobService = wcsGetWmsJobService;
            _IPlcConnectionPoolService = plcConnectionPoolService;
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            logUtil.Info("======开始启动程序======");
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Zocono.WCS.HangfireHost v1"));
            
            MyPrograme myPrograme = Configuration.GetSection("MyPrograme").Get<MyPrograme>();

            //加载当前程序关联的所有PLC连接到连接池，一次执行。
            //将所有程序放到一个集合中，方便plc连接
            List<string> list = new();
            if (myPrograme != null)
            {
                try
                {
                    foreach (var Programe in myPrograme.ProgrameName.Pro_1001)
                    {
                        list.Add(Programe);
                    }
                    foreach (var Programe in myPrograme.ProgrameName.Pro_2001)
                    {
                        list.Add(Programe);
                    }
                    foreach (var Programe in myPrograme.ProgrameName.Pro_3001)
                    {
                        list.Add(Programe);
                    }
                    foreach (var Programe in myPrograme.ProgrameName.Pro_4001)
                    {
                        list.Add(Programe);
                    }
                    foreach (var Programe in myPrograme.ProgrameName.Pro_5001)
                    {
                        list.Add(Programe);
                    }
                }
                catch
                {
                }
            }
            //初始化 hangfire
            InitHangfireJob(app, serviceProvider, myPrograme, list, logUtil);
            InitQuartzJob(myPrograme, list, logUtil);

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseCors("all");

            app.UseStaticFiles();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHub<EquipmentSignalRService>("/equipmentSignalRService");
            });
            ServiceProviderInstance.Instance = app.ApplicationServices;
        }

        private void InitHangfireJob(IApplicationBuilder app, IServiceProvider serviceProvider, MyPrograme myPrograme, List<string> list, ILogUtil logUtil)
        {
            string JobType = Configuration["JobType"];
            if (JobType == "2")
            {
                return;
            }
            logUtil.Info("使用Hangfire定时作业");
            //定时间隔
            int readDBInterval = Configuration["ReadDBInterval"].ToInt32();
            int heardInterval = Configuration["HeardInterval"].ToInt32();
            int reconnectInterval = Configuration["ReconnectInterval"].ToInt32();
            //读取监控DB间隔
            int readDBMonitorInterval = Configuration["ReadDBMonitorInterval"].ToInt32();
            // Configure hangfire to use the new JobActivator we defined.
            GlobalConfiguration.Configuration.UseActivator(new HangfireActivator(serviceProvider));
            //清除服务
            RemoveAllhangfireServer();
            app.UseHangfireDashboard("/hangfire", new DashboardOptions()
            {
                // UI 账号密码登录  在配置中
                Authorization = new BasicAuthAuthorizationFilter[] {
                      new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){
                           SslRedirect=false,
                            RequireSsl=false,
                             Users=new BasicAuthAuthorizationUser[]{
                                  new BasicAuthAuthorizationUser(){
                                      Login = Configuration["Hangfire:Login"],
                                      PasswordClear = Configuration["Hangfire:PasswordClear"]
                                  }
                             }
                      })
                }
            });
            //清除任务
            RemoveAllHangfireJobs();
            #region PLC连接池 线程
            //设置当地时间
            RecurringJob.AddOrUpdate(() => Console.WriteLine($"APS.NET Core Hangfire"), Cron.Hourly(), TimeZoneInfo.Local);

            //连接池
            //BackgroundJob.Enqueue<PlcConnetionPoolService>(p => p.S7LoadAllPlcConnections(list));
            ////路径
            //BackgroundJob.Enqueue<RouteInfoService>(p => p.GetRouteInfoListFromRedisAsync());
            ////路径详情
            //BackgroundJob.Enqueue<RouteDetailInfoService>(p => p.GetRouteDetailInfoListAsync());
            ////写配置
            //BackgroundJob.Enqueue<PlcWriteDbInfoService>(p => p.GetPlcWriteDbInfoListAsync());
            BackgroundJob.Enqueue<InitPlcConnectPoolJob>(p => p.HangfireJob(list));
            BackgroundJob.Enqueue<OnceJobQz>(q => q.HangfireJob());


            if (myPrograme != null)
            {
                ////连接池心跳服务
                //RecurringJob.AddOrUpdate<PlcConnetionPoolService>($"{myPrograme.ProgrameName} 连接池心跳服务", p => p.S7Heartbeat(list), $"*/{heardInterval} * * * * ?");//连接状态插入或跟新到表格

                ////PLC重连接，30秒1次
                //RecurringJob.AddOrUpdate<PlcConnetionPoolService>($"{myPrograme.ProgrameName} 连接池重连接服务", p => p.S7ReLoadPlcConnection(), $"*/{reconnectInterval} * * * * ?");
                //心跳连接
                RecurringJob.AddOrUpdate<HeartJob>($"{myPrograme.ProgrameName} 连接池心跳服务", p => p.HangfireJob(list), $"*/{heardInterval} * * * * ?");
                //PLC重连接，30秒1次
                RecurringJob.AddOrUpdate<PlcReconnectJob>($"{myPrograme.ProgrameName} 连接池重连接服务", p => p.HangfireJob(), $"*/{reconnectInterval} * * * * ?");
            }
            ////获取下架移库消防任务
            //RecurringJob.AddOrUpdate<WcsGetWmsJobService>($"WMS下发WCS作业", p => p.WCSGetWMSInitialWorkTaskAsync(), "*/10 * * * * ?");
            //获取下架移库消防任务
            RecurringJob.AddOrUpdate<GetWmsTaskToWcsJob>($"WMS下发WCS作业", p => p.HangfireJob(), "*/10 * * * * ?");

            ////定时把堆垛机未执行任务放到缓存中
            //RecurringJob.AddOrUpdate<WcsGetWmsJobService>($"堆垛机未执行任务放到缓存中", p => p.GetInitWorkTaskToMemory(), "*/1 * * * * ?");
            //定时把堆垛机未执行任务放到缓存中
            RecurringJob.AddOrUpdate<GetScWorkTaskToMeJob>($"堆垛机未执行任务放到缓存中", p => p.HangfireJob(), "*/1 * * * * ?");

            #endregion

            #region 交互Job读取PLC数据
            if (myPrograme != null)
            {
                //第三层楼
                foreach (var item in myPrograme.ProgrameName.Pro_3001)
                {
                    foreach (var job in myPrograme.Jobs.Job3001)
                    {
                        //RecurringJob.AddOrUpdate<JobExcutorService>($"Programe:{item},Job:{job} 启动",
                        //j => j.ReadPlcDbJobAsync(item, job), $"*/{readDBInterval} * * * * ?");
                        RecurringJob.AddOrUpdate<RepeatReadDbJob>($"Programe:{item},Job:{job} 启动",
                        j => j.HangfireJob(item, job), $"*/{readDBInterval} * * * * ?");
                    }
                }
                //第4层楼
                foreach (var item in myPrograme.ProgrameName.Pro_4001)
                {
                    foreach (var job in myPrograme.Jobs.Job4001)
                    {
                        //RecurringJob.AddOrUpdate<JobExcutorService>($"Programe:{item},Job:{job} 启动",
                        //j => j.ReadPlcDbJobAsync(item, job), $"*/{readDBInterval} * * * * ?");
                        RecurringJob.AddOrUpdate<RepeatReadDbJob>($"Programe:{item},Job:{job} 启动",
                        j => j.HangfireJob(item, job), $"*/{readDBInterval} * * * * ?");
                    }
                }
                //第5层楼
                foreach (var item in myPrograme.ProgrameName.Pro_5001)
                {
                    foreach (var job in myPrograme.Jobs.Job5001)
                    {
                        //RecurringJob.AddOrUpdate<JobExcutorService>($"Programe:{item},Job:{job} 启动",
                        //j => j.ReadPlcDbJobAsync(item, job), $"*/{readDBInterval} * * * * ?");
                        RecurringJob.AddOrUpdate<RepeatReadDbJob>($"Programe:{item},Job:{job} 启动",
                        j => j.HangfireJob(item, job), $"*/{readDBInterval} * * * * ?");
                    }
                }
                //第2层楼
                foreach (var item in myPrograme.ProgrameName.Pro_2001)
                {
                    foreach (var job in myPrograme.Jobs.Job2001)
                    {
                        //RecurringJob.AddOrUpdate<JobExcutorService>($"Programe:{item},Job:{job} 启动",
                        //j => j.ReadPlcDbJobAsync(item, job), $"*/{readDBInterval} * * * * ?");
                        RecurringJob.AddOrUpdate<RepeatReadDbJob>($"Programe:{item},Job:{job} 启动",
                        j => j.HangfireJob(item, job), $"*/{readDBInterval} * * * * ?");
                    }
                }
                //第1层楼
                foreach (var item in myPrograme.ProgrameName.Pro_1001)
                {
                    foreach (var job in myPrograme.Jobs.Job1001)
                    {
                        //RecurringJob.AddOrUpdate<JobExcutorService>($"Programe:{item},Job:{job} 启动",
                        //j => j.ReadPlcDbJobAsync(item, job), $"*/{readDBInterval} * * * * ?");
                        RecurringJob.AddOrUpdate<RepeatReadDbJob>($"Programe:{item},Job:{job} 启动",
                        j => j.HangfireJob(item, job), $"*/{readDBInterval} * * * * ?");
                    }
                }
            }

            #endregion

            //RecurringJob.AddOrUpdate<IProcessPlanarService>("定时同步表PlanarProcessServiceMapInfo数据到内存", p => p.ReloadPlanarActionMessage(), "0 0/2 * * * ?");//每2分钟同步一次
            #region  监控数据读取

            ////获取监控配置Job
            //var equipmentStates = Configuration.GetSection("EquipmentState").Get<List<EquipmentState>>();
            ////执行读取监控数据定时任务
            //foreach (var item in equipmentStates)
            //{
            //    RecurringJob.AddOrUpdate<JobExcutorService>($"Programe:{item.ProgrameName} 读取监控数据定时任务启动",
            //    j => j.ReadPlcDbMonitorAsync(item.ProgrameName, item.Jobs), $"*/{readDBInterval} * * * * ?");
            //}

            RecurringJob.AddOrUpdate<RepeatGetTableDataJob>($"读取监控数据定时任务启动",
                j => j.HangfireJob(), $"*/{readDBMonitorInterval} * * * * ?");
            //RecurringJob.AddOrUpdate<RepeatGetTableDataJobInvoking>($"读取监控数据定时任务启动",
           // j => j.HangfireJob(), $"*/{readDBMonitorInterval} * * * * ?");
            #endregion
        }

        private async void InitQuartzJob(MyPrograme myPrograme, List<string> list,ILogUtil logUtil)
        {
            //定时间隔
            int readDBInterval = Configuration["ReadDBInterval"].ToInt32();
            int heardInterval = Configuration["HeardInterval"].ToInt32();
            int reconnectInterval = Configuration["ReconnectInterval"].ToInt32();
            string JobType = Configuration["JobType"];
            if (JobType != "2")
            {
                return;
            }
            logUtil.Info("使用Quartz定时作业");
            //QZ任务设置
            var _provider = _services.BuildServiceProvider();
            try
            {
                ISchedulerFactory _schedulerFactory = _provider.GetService<ISchedulerFactory>();
                var _scheduler = await _schedulerFactory.GetScheduler();
                var _jobFactory = _provider.GetService<IJobFactory>();
                _scheduler.JobFactory = _jobFactory;
                await _scheduler.Start();
                var _quartzHelp = new QuartzHelp();

                //连接成字符串传入
                string myProgrameString = string.Join("-", list);
                JobDataMap jobDataMap = new JobDataMap();
                jobDataMap["myPrograme"] = myProgrameString;

                #region 初始化PLC连接池
                IJobDetail initPlcConnectJob = _quartzHelp.CreateJob(typeof(QuartzInitPlcConnectPoolJob), "初始化PLC连接", "initPlcConnectJob", jobDataMap, true);
                ITrigger initPlcConnectTrigger = _quartzHelp.CreateTrigger("初始化PLC连接", "initPlcConnectJob", initPlcConnectJob);
                await _scheduler.ScheduleJob(initPlcConnectJob, initPlcConnectTrigger);
                #endregion

                #region 调试心跳作业
                IJobDetail heartJob = _quartzHelp.CreateJob(typeof(QuartzHeartJob), "WCS-PLC心跳", "heartJob", jobDataMap, true);
                ITrigger heartTrigger = _quartzHelp.CreateTrigger("HeartJob", "heartJob", $"*/{heardInterval} * * * * ?", heartJob, l => l.WithMisfireHandlingInstructionIgnoreMisfires());
                await _scheduler.ScheduleJob(heartJob, heartTrigger);
                #endregion

                #region 一次性作业
                IJobDetail onceJob = _quartzHelp.CreateJob(typeof(QuartzOnceJobQz), "一次性作业", "OnceJob", true);
                ITrigger onceTrigger = _quartzHelp.CreateTrigger("一次性作业", "OnceJob", onceJob);
                await _scheduler.ScheduleJob(onceJob, onceTrigger);
                #endregion

                #region 多次读取作业
                IJobDetail multipleJob = _quartzHelp.CreateJob(typeof(QuartzRepeatGetTableDataJob), "多次读取作业", "RepeatGetTableDataJob", true);
                ITrigger multipleTrigger = _quartzHelp.CreateTrigger("多次读取作业", "RepeatGetTableDataJob", $"*/{readDBInterval} * * * * ?", multipleJob, l => l.WithMisfireHandlingInstructionIgnoreMisfires());
                await _scheduler.ScheduleJob(multipleJob, multipleTrigger);
                #endregion

                #region 获取WMS下发任务作业
                IJobDetail getWmsTaskJob = _quartzHelp.CreateJob(typeof(QuartzGetWmsTaskToWcsJob), "获取WMS下发任务作业", "GetWmsTaskToWcsJob", true);
                ITrigger getWmsTaskTrigger = _quartzHelp.CreateTrigger("获取WMS下发任务作业", "GetWmsTaskToWcsJob", "*/10 * * * * ?", getWmsTaskJob, l => l.WithMisfireHandlingInstructionIgnoreMisfires());
                await _scheduler.ScheduleJob(getWmsTaskJob, getWmsTaskTrigger);
                #endregion

                #region 获取堆垛机未执行任务到缓存
                IJobDetail getScWorkJob = _quartzHelp.CreateJob(typeof(QuartzGetScWorkTaskToMeJob), "获取堆垛机未执行任务到缓存", "GetScWorkTaskToMeJob", true);
                ITrigger getScWorkTrigger = _quartzHelp.CreateTrigger("获取堆垛机未执行任务到缓存", "GetScWorkTaskToMeJob", $"*/{readDBInterval} * * * * ?", getScWorkJob, l => l.WithMisfireHandlingInstructionIgnoreMisfires());
                await _scheduler.ScheduleJob(getScWorkJob, getScWorkTrigger);
                #endregion

                #region 连接池重连接服
                IJobDetail plcReconnectJob = _quartzHelp.CreateJob(typeof(QuartzPlcReconnectJob), "连接池重连接服", "plcReconnectJob", true);
                ITrigger plcReconnectTrigger = _quartzHelp.CreateTrigger("获取WMS下发任务作业", "plcReconnectJob", "*/20 * * * * ?", plcReconnectJob, l => l.WithMisfireHandlingInstructionIgnoreMisfires());
                await _scheduler.ScheduleJob(plcReconnectJob, plcReconnectTrigger);
                #endregion

                #region 定时读取DB作业
                if (myPrograme != null)
                {
                    //第1层楼
                    foreach (var item in myPrograme.ProgrameName.Pro_1001)
                    {
                        foreach (var job in myPrograme.Jobs.Job1001)
                        {
                            await SetReadDBQuartzJob(_quartzHelp, _scheduler, item, job, readDBInterval);
                        }
                    }
                    //第2层楼
                    foreach (var item in myPrograme.ProgrameName.Pro_2001)
                    {
                        foreach (var job in myPrograme.Jobs.Job2001)
                        {
                            await SetReadDBQuartzJob(_quartzHelp, _scheduler, item, job, readDBInterval);
                        }
                    }
                    //第三层楼
                    foreach (var item in myPrograme.ProgrameName.Pro_3001)
                    {
                        foreach (var job in myPrograme.Jobs.Job3001)
                        {
                            await SetReadDBQuartzJob(_quartzHelp, _scheduler, item, job, readDBInterval);
                        }
                    }
                    //第4层楼
                    foreach (var item in myPrograme.ProgrameName.Pro_4001)
                    {
                        foreach (var job in myPrograme.Jobs.Job4001)
                        {
                            await SetReadDBQuartzJob(_quartzHelp, _scheduler, item, job, readDBInterval);
                        }
                    }
                    //第5层楼
                    foreach (var item in myPrograme.ProgrameName.Pro_5001)
                    {
                        foreach (var job in myPrograme.Jobs.Job5001)
                        {
                            await SetReadDBQuartzJob(_quartzHelp, _scheduler, item, job, readDBInterval);
                        }
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                var _log = _provider.GetService<ILogUtil>();
                _log.Error(ex.ToString());
            }
        }

        /// <summary>
        /// 设置读DB定时作业
        /// </summary>
        /// <param name="quartzHelp"></param>
        /// <param name="scheduler"></param>
        /// <param name="programeCode"></param>
        /// <param name="jobName"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        private async Task SetReadDBQuartzJob(IQuartzHelp quartzHelp, IScheduler scheduler, string programeCode, string jobName, int interval)
        {
            JobDataMap jobDataMapJob = new JobDataMap();
            jobDataMapJob["programeCode"] = programeCode;
            jobDataMapJob["jobName"] = jobName;

            #region 多次读取PLC数据
            IJobDetail multipleJob = quartzHelp.CreateJob(typeof(QuartzRepeatReadDbJob), $"Programe:{programeCode},Job:{jobName}", "RepeatGetTableDataJob", jobDataMapJob, true);
            ITrigger multipleTrigger = quartzHelp.CreateTrigger($"Programe:{programeCode},Job:{jobName}", "RepeatGetTableDataJob", $"*/{interval} * * * * ?", multipleJob, l => l.WithMisfireHandlingInstructionIgnoreMisfires());
            await scheduler.ScheduleJob(multipleJob, multipleTrigger);
            #endregion
        }

        /// <summary>
        /// 删除超过2秒没活动的hangfire服务 以解决每次重启还保留上一次的任务
        /// </summary>
        private void RemoveAllhangfireServer()
        {
            try
            {
                var varMonitoringApi = JobStorage.Current.GetMonitoringApi();
                
                JobStorage.Current.GetConnection().RemoveTimedOutServers(new TimeSpan(0, 0, 2));
            }
            catch (Exception e)
            {
                Console.WriteLine($"APS.NET Core Hangfire = {e.Message}");


            }

        }
        /// <summary>
        /// 删除所有的job 任务 防止重启还保留上次的任务
        /// </summary>
        private async void RemoveAllHangfireJobs()
        {
            try
            {
                var hangfireMonitor = JobStorage.Current.GetMonitoringApi();

                var hangfireConnection = JobStorage.Current.GetConnection();
                //RecurringJobs
                hangfireConnection.GetRecurringJobs().ForEach(xx => RecurringJob.RemoveIfExists(xx.Id));

                //ProcessingJobs
                hangfireMonitor.ProcessingJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));

                //ScheduledJobs
                hangfireMonitor.ScheduledJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));

                //EnqueuedJobs
                var list = hangfireMonitor.Queues().ToList();
                for (int i = 0; i < list.Count; i++)
                {
                    //每次处理数据不能超过2100 所以分段去处理
                    var isWhile = true;
                    while (isWhile)
                    {
                        var eqCounts = hangfireMonitor.EnqueuedJobs(list[i].Name, 0, 2009).Count;
                        list.ForEach(xx => hangfireMonitor.EnqueuedJobs(xx.Name, 0, 2009).ForEach(x => BackgroundJob.Delete(x.Key)));
                        if (eqCounts <= 0)
                        {
                            isWhile = false;
                        }
                        await Task.Delay(10);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"APS.NET Core Hangfire = {e.Message}");
            }



        }


    }
}
